<template>
	<view>
		<!-- 导航栏 -->
		<free-nav-bar :title="detail.name" :noreadnum="totalNoreadnum" showBack>
			<free-icon-button  slot="right" :icon="'\ue6fd'" 
			@click="openChatSet"></free-icon-button>
		</free-nav-bar>
		
		<!-- 聊天内容区域 (滚动) -->
		<scroll-view scroll-y class="bg-light position-fixed left-0 right-0 px-3 no-scrollbar"  
			style="bottom: 105rpx; box-sizing: border-box;" :style="chatBodyBottom" 
			:show-scrollbar="false" @click="clickPage" 
			:scroll-into-view="scrollIntoView" :scroll-with-animation="true">
			<!-- 聊天信息列表组件 -->
			<view v-for="(item,index) in list" :key="index" :id="'chatItem_'+index">
				<free-chat-item :item="item" :index="index"  ref="chatItem"
				:pretime="index > 0 ? list[index-1].create_time : 0"
				@long="long" @preview="previewImage" :shownickname="currentChatitem.shownickname"></free-chat-item>
			</view>
			<view style="width: 100%; height: 20rpx;"></view>
		</scroll-view>
		<!-- 点击页面收起扩展菜单 因为scroll-view点击事件在app不生效，需要用到div -->
		<!-- #ifdef APP-PLUS-NVUE -->
		<div class="position-fixed left-0 right-0 top-0 bottom-0"
		:style="'bottom:'+getMaskBottom+'px;'"
		@click="clickPage" v-if="mode === 'action' || mode === 'emoticon'"></div>
		<!-- #endif -->
		<!-- 长按弹出操作菜单 -->
		<free-popup ref="extend" :bodyW="240" :bodyH="450" :tabbarHeight="105">
			<view class="flex flex-column" style="width: 240rpx;" :style="getMenusStyle">
				<view class="flex-1 flex align-center" hover-class="bg-light"
				v-for="(item,index) in menusList" :key="index"
				@click="clickEvent(item.event)">
					<text class="font-md pl-3">{{item.name}}</text>
				</view>
			</view>
		</free-popup>
		
		<!-- 底部输入框 -->
		<view class="position-fixed left-0 right-0 border-top flex align-center" 
		style="background-color: #f7f7f6; height: 105rpx;" :style="'bottom:'+keyboardHeight+'px;'">
			<free-icon-button v-if="mode === 'audio'" :icon="'\ue607'" 
			@click="changeVoiceOrText"></free-icon-button>
			<free-icon-button v-else :icon="'\ue606'"
			@click="changeVoiceOrText"></free-icon-button>
			<!-- 输入框 -->
			<view class="flex-1">
				<view v-if="mode === 'audio'" class="rounded flex align-center justify-center" 
				style="height: 75rpx;" :class="isRecording ? 'bg-hover-light':'bg-white'" 
				@touchstart="voiceTouchStart" @touchend="voiceTouchEnd" @touchcancel="voiceTouchCancel" @touchmove="voiceTouchMove">
					<text class="font">{{isRecording ? '松开 结束' : '按住 说话'}}</text>
				</view>
				
				<textarea v-else fixed class="border bg-white font-md rounded p-1" 
				style="height: 50rpx; max-width: 450rpx;" adjust-position="false" v-model="text" 
				@click="onInputFocus" auto-blur @focus="focus"/>
			</view>
			<!-- 表情 -->
			<free-icon-button :icon="'\ue605'" 
			@click="openActionOrEmoticon('emoticon')"></free-icon-button>
			<!-- 扩展菜单 -->
			<free-icon-button v-if="text.length === 0" 
			:icon="'\ue603'" @click="openActionOrEmoticon"></free-icon-button>
			<!-- 发送按钮 -->
			<view  v-else class="flex-shrink">
				<free-main-button name="发送" @click="send('text')"></free-main-button>
			</view>
		</view>
		
		<!-- 扩展菜单 -->
		<free-popup ref="action" bottom transformOrigin="center bottom"
		@hide="keyboardHeight = 0" :mask="false">
			<view class="border-top border-light-secondary bg-light" style="height: 580rpx;">
				<!-- 使用轮播图组件做扩展菜单 -->
				<swiper :indicator-dots="emoticonOrActionList.length > 1" 
				:duration="1000" style="height: 530rpx;">
					<swiper-item class="row" 
					v-for="(item,index) in emoticonOrActionList" :key="index">
						<view class="col-3 flex flex-column align-center justify-center" 
						style="height: 255rpx;" v-for="(item2,index2) in item" :key="index2" 
						@click="actionEvent(item2)">
							<image :src="item2.icon" mode="widthFix" 
							style="width: 100rpx; height: 100rpx;"></image>
							<text class="font-sm text-light-black mt-2">{{item2.name}}</text>
						</view>
					</swiper-item>
				</swiper>
			</view>
		</free-popup>
	
		<!-- 录音提示模态框 -->
		<view class="position-fixed top-0 left-0 right-0 flex align-center justify-center" 
		style="bottom: 105rpx;" v-if="isRecording">
			<view class="rounded flex flex-column align-center justify-center" style="width: 360rpx; height: 360rpx; background-color: rgba(0, 0, 0, 0.5);">
				<image src="/static/audio/recording.gif" style="width: 150rpx; height: 150rpx;"></image>
				<text class="font text-white mt-3">{{unRecord ? '松开手指，取消发送':'手指上滑，取消发送'}}</text>
			</view>
		</view>
	</view>
</template>

<script>
	// #ifdef APP-PLUS-NVUE
	// 获取dom模块 用于调节聊天内容到最底部
	const dom = weex.requireModule('dom')
	// #endif
	
	import freeNavBar from "@/components/free-ui/free-nav-bar.vue"
	import freeIconButton from "@/components/free-ui/free-icon-button.vue"
	import freeChatItem from "@/components/free-ui/free-chat-item.vue"
	import freePopup from "@/components/free-ui/free-popup.vue"
	import freeMainButton from "@/components/free-ui/free-main-button.vue"
	
	import {mapState,mapMutations} from 'vuex'
	import $U from '@/common/free-lib/util.js';
	import $H from '@/common/free-lib/request.js';
	import auth from '@/common/mixin/auth.js';
	export default {
		data() {
			return {
				scrollIntoView:'',
				// 输入模式 text文字 emotion表情 action操作菜单 audio音频
				mode:"text",
				navBarHeight:0,
				// 长按扩展菜单
				menusList:[],
				// 所有消息
				list:[],
				// 当前操作的索引
				propIndex: -1,
				// 软键盘高度
				keyboardHeight: 0,
				// 要发送的消息
				text: '',	
				// 扩展菜单
				actionList:[
					[{
						name:"相册",
						icon:"/static/images/extends/pic.png",
						event:"uploadImage"
					},
					{
						name:"拍摄",
						icon:"/static/images/extends/video.png",
						event:"uploadVideo"
					},
					{
						name:"收藏",
						icon:"/static/images/extends/shoucan.png",
						event:"openFava"
					},
					{
						name:"名片",
						icon:"/static/images/extends/man.png",
						event:"sendCard"
					},
					{
						name:"语音通话",
						icon:"/static/images/extends/phone.png",
						event:""
					},
					{
						name:"位置",
						icon:"/static/images/extends/path.png",
						event:""
					}],
					[{
						name:"相册",
						icon:"/static/images/extends/pic.png",
						event:""
					},
					{
						name:"拍摄",
						icon:"/static/images/extends/video.png",
						event:""
					},
					{
						name:"收藏",
						icon:"/static/images/extends/shoucan.png",
						event:""
					},
					{
						name:"名片",
						icon:"/static/images/extends/man.png",
						event:""
					},
					{
						name:"语音通话",
						icon:"/static/images/extends/phone.png",
						event:""
					},
					{
						name:"位置",
						icon:"/static/images/extends/path.png",
						event:""
					}]
				],
				// 表情包
				emoticonList:[],
				// 音频录制状态
				isRecording: false,
				// 录音第一次点的位置
				recordingStartY:0,
				// 是否取消录音
				unRecord: false,
				
				detail:{
					id:0,
					name:"",
					avatar:"",
					chat_type: "user"
				},
				screenHeight:0
			}
		},
		mixins:[auth],
		onLoad(e) {
			if(!e.params) return this.backToast
			this.detail = JSON.parse(decodeURIComponent(e.params))
			// 初始化表情包
			this.__init()
			// 创建聊天对象
			this.chat.createChatObject(this.detail)
			// 获取历史记录(不考录分页)
			this.list = this.chat.getChatDetail()
			
			// #ifdef H5
			this.screenHeight = window.innerHeight
			// #endif
			
			// 监听接收聊天信息
			uni.$on('onMessage', this.onMessage)
			
			uni.$on('updateHistory', this.updateHistory)
			
			// 监听发送收藏和名片 
			uni.$on('sendItem', this.onSendItem)
		},
		destroyed() {
			// 销毁聊天对象
			this.chat.destoryChatObject()
			// 销毁监听接收聊天信息
			uni.$off('onMessage', this.onMessage)
			uni.$off('updateHistory', this.updateHistory)
			uni.$off('sendItem', this.onSendItem)
		},
		mounted() {
			let statusBarHeight = 0
			// 动态来获取状态栏的高度
			// #ifdef APP-PLUS-NVUE
			statusBarHeight = plus.navigator.getStatusbarHeight()
			// #endif
			this.navBarHeight = statusBarHeight + uni.upx2px(90)  // rpx转px
			
			
			// 监听键盘高度变化 （小程序）
			uni.onKeyboardHeightChange(res =>{
				if(this.mode !== 'action' && this.mode !== 'emoticon')
					this.keyboardHeight = res.height
				if(this.keyboardHeight > 0)
					this.pageToBottom()
			})
			// 跳到底部
			this.pageToBottom()
			
			// 注册发送音频事件
			this.regSendVoiceEvent((url)=>{
				if(!this.unRecord){
					this.send('audio', url,{
						time: this.recordTime
					})
				}
			})
		},
		methods: {
			...mapMutations(['regSendVoiceEvent']),
			// 发送收藏和名片 
			onSendItem(e){
				if(e.sendType === 'fava' || e.sendType === 'card'){
					console.log("onSendItem")
					this.send(e.type, e.data, e.options)
				}
			},
			
			// 更新历史记录
			updateHistory(isclear = true){
				if(isclear){
					this.list = []
				}else{
					// 获取历史记录(不考录分页)
					this.list = this.chat.getChatDetail()
				}
			},
			// 监听接收聊天信息
			onMessage(message){
				if((message.from_id === this.detail.id && message.chat_type === 'user') || (message.chat_type === 'group' && message.to_id === this.detail.id)){
					//接收消息
					if(message.isremove !== 1){ 
						this.list.push(message)
						// 置于底部
						return this.pageToBottom()
					}
					// 撤回消息
					
					let index = this.list.findIndex(item=>item.id === message.id)
					if(index !== -1){
						console.log("监听监听接收聊天信息")
						this.list[index].isremove = 1
					}
				}
			},
			
			
			// 初始化
			__init(){
				// 初始化表情包
				let total = 20
				let page = Math.ceil(total/8)
				let arr = []
				for(let i = 0; i < page; i++){
					let start = i*8
					arr[i] = []
					for(let j = 0; j < 8; j++){
						let no = start + j;
						if((no + 1) > total) continue;
						arr[i].push({
							name:"表情"+no,
							icon:"/static/images/emoticon/5497/"+no+".gif",
							event:"sendEmoticon"
						})
					}
				}
				this.emoticonList = arr
				
				// 初始化会话列表
				this.chat.initChatListItem({
					chat_type: this.detail.chat_type,
					to_id: this.detail.id,
					to_name: this.detail.name,
					to_avatar: this.detail.avatar,
					data: this.detail.chat_type === 'user' ? '你们已经是好友，可以开始聊天了' : '你已经加入群聊，可以开始聊天了'
				})
			},
			//打开扩展菜单或者表情包
			openActionOrEmoticon(mode = 'action'){
				this.mode = mode
				this.$refs.action.show()
				// 收起键盘
				uni.hideKeyboard()
				this.keyboardHeight = uni.upx2px(580)
			},
			// 输入框聚焦
			onInputFocus(){
				this.mode = 'text'
			},
			// 发送消息
			send(type, data = '',options={}){
				// 组织数据格式
				switch (type){
					case 'text':
						data = data || this.text
						break;
				}
				let message = this.chat.formatsendData({
					type,
					data,
					options
				})
				// 渲染到页面
				let index = this.list.length
				this.list.push(message)
				// 监听上传进度
				let onProgress = false
				if(message.type !== 'text' && message.type !== 'emoticon' && message.type !== 'cart' && message.data.startsWith('http')){
					onProgress = (progress)=>{
						console.log('上传进度:',progress)
					}
				}
				// 发送消息
				this.chat.send(message, onProgress).then(res=>{
					// 发送成功
					this.list[index].id = res.id
					this.list[index].sendStatus = 'success'
					console.log(res)
				}).catch(err=>{
					// 发送失败
					this.list[index].sendStatus = 'fail'
					console.log(err)
				})
				// 清空输入框
				if(type === 'text') this.text = ''
				
				// 置于底部
				this.pageToBottom()
			},
			// 回到底部
			pageToBottom(){
				// #ifdef APP-PLUS-NVUE
				let chatitem = this.$refs.chatItem
				// 获取最后一条消息位置
				let lastIndex = chatitem.length > 0 ?  chatitem.length -1 : 0
				if(chatitem[lastIndex]){
					dom.scrollToElement(chatitem[lastIndex], {})
				}
				// #endif
				// #ifndef APP-PLUS-NVUE
				setTimeout(()=>{
					let lastIndex = this.list.length -1
					this.scrollIntoView = 'chatItem_'+lastIndex
				},300)
				// #endif
			},
			// 长按消息气泡
			long({x, y, index}){
				// 初始化索引
				this.propIndex = index
				// 组装菜单
				let menus = [
					{
						name: "发给朋友",
						event: "sendToChatItem"
					},
					{
						name: "收藏",
						event: "fava"
					},
					{
						name: "删除",
						event: "delete"
					}]
					let item = this.list[this.propIndex]
					let isSelf = this.user.id === item.from_id
					if(isSelf){
						menus.push({
							name: "撤回",
							event: "removeChatItem"
						})
					}
					if(item.type === 'text'){
						menus.unshift({
							name: "复制",
							event: "copy"
						})
					}
					this.menusList = menus
				
				// 显示扩展菜单的位置
				this.$refs.extend.show(x, y, index)
			},
			// 操作菜单方法
			clickEvent(event){
				// 拿到当前被操作的信息
				let item = this.list[this.propIndex]
				let isSelf = this.user.id === item.from_id
				switch(event){
					case "removeChatItem":  //撤回消息
					this.chat.recall(item).then((res)=>{
						console.log(res,item)
						item.isremove = 1
						console.log(res,item.isremove)
					})
						break;
					case 'sendToChatItem': //发给朋友
					uni.navigateTo({
						url: './chat-list/chat-list?params='+encodeURIComponent(JSON.stringify(item))
					})
						break;
					case 'copy':	//复制
					uni.setClipboardData({
						data: item.data,
						showToast: true,
						success: function () {
							
						}
					});
						break;
					case 'delete':
					uni.showModal({
						content: '是否要删除该消息记录?',
						success: (res) => {
							if (!res.confirm) return;
							this.chat.deleteChatDetailItem(item,isSelf)
							this.list.splice(this.propIndex, 1)
							// 如果删除的是最后一条消息
							if(this.list.length === this.propIndex){
								this.chat.updateChatItem({
									id: this.detail.id,
									chat_type: this.detail.chat_type
								}, (v)=>{
									let o = this.list[this.propIndex - 1]
									let data = ''
									if(o){
										data = this.chat.formatChatItemData(o, isSelf)
									}
									v.data = data
									return v
								})
							}
							
						}
					})
						break;
					case 'fava':	// 加入收藏
					uni.showModal({
						content: '是否要加入收藏?',
						success: (res) => {
							if (res.confirm){
								$H.post('/fava/create', {
									type: item.type,
									data: item.data	,
									options: JSON.stringify(item.options)
								}).then((res)=>{
									uni.showToast({
										title: '加入收藏成功'
									});
								})
							}
						}
					})
						break;
					default:
						break;
				}
				// 关闭菜单
				this.$refs.extend.hide()
			},
			// 扩展菜单方法
			actionEvent(e){
				switch (e.event){
					case 'uploadImage':  //选择相册发送图片 
						uni.chooseImage({
							count: 9,
							sourceType:['album'],
							success:(res)=>{
								// 发送服务器
								
								// 渲染到页面
								res.tempFilePaths.forEach(item=>{
									this.send('image',item)
								})
							}
						})
						break;
					case 'uploadVideo':  //发送短视频	
						uni.chooseVideo({
							success: (res) => {
								// 发送服务器
								
								// 渲染到页面
								this.send('video',res.tempFilePath)
								// 修改本地发送状态
							}
						})
						break;
					case 'sendEmoticon':  //发送表情包
						this.send('emoticon', e.icon)
						break;
					case 'openFava':	//发送收藏
						uni.navigateTo({
							url: '/pages/my/fava/fava?type=send'
						})
						break;
					case 'sendCard': 	// 发送名片
						uni.navigateTo({
							url: '/pages/mail/mail/mail?type=sendCard&limit=1'
						})
						break;
					default:
						break;
				}
			},
			// 点击页面
			clickPage(){
				this.mode = ''
			},
			// 预览图片
			previewImage(url){
				uni.previewImage({
					current:url,
					urls: this.imageList,
					indicator: "default"
				})
			},
			// 切换音频录制和文本输入
			changeVoiceOrText(){
				this.mode = this.mode !== 'audio' ? 'audio' : 'text'
			},
			// 录音相关
			// 录音开始
			voiceTouchStart(e){
				// 初始化
				this.isRecording = true
				this.recordingStartY = e.changedTouches[0].screenY
				this.unRecord = false
				// 开始录音
				this.RECORD.start({
					format: 'mp3'
				})
			},
			// 松开
			voiceTouchEnd(){
				this.isRecording = false
				// 停止录音
				this.RECORD.stop()
				
			},
			// 被打断
			voiceTouchCancel(){
				this.isRecording = false
				this.unRecord = true
				// 停止录音
				this.RECORD.stop()
			},
			// 手指移动
			voiceTouchMove(e){
				let Y = Math.abs(e.changedTouches[0].screenY - this.recordingStartY)
				this.unRecord = (Y >= 80)
			},
			// 打开聊天信息设置页
			openChatSet(){
				uni.navigateTo({
					url:"./chat-set/chat-set?params="+JSON.stringify({
						id: this.detail.id,
						chat_type: this.detail.chat_type
					})
				})
			},
			focus(e){
				this.mode = 'text'
				
			}
		}, 
		computed:{
			...mapState({
				user: state=>state.user.user,
				chatList: state=>state.user.chatList,
				RECORD: state=>state.audio.RECORD,
				recordTime: state=>state.audio.recordTime,
				chat: state=>state.user.chat,
				totalNoreadnum: state=>state.user.totalNoreadnum
			}),
			// 拿到当前会话配置信息
			currentChatitem(){
				let index = this.chatList.findIndex(item=>item.id === this.detail.id && item.chat_type === this.detail.chat_type)
				if(index !== -1){
					return this.chatList[index]
				}
				return {}
			},
			// 动态获取蒙版的位置
			getMaskBottom(){
				return this.keyboardHeight + uni.upx2px(105)
			},
			// 动态获取菜单高度
			getMenusHeight() {
				let H = 100
				return this.menusList.length * H
			},
			// 获取菜单样式
			getMenusStyle(){
				return `height:${this.getMenusHeight}rpx`
			},
			
			// 判断是否是本人
			isdoSelf(){
				let id = 1
				let user_id = this.propIndex > -1 ? this.list[this.propIndex].user_id : 0
				return user_id === id
			},
			
			// 聊天区域bottom
			chatBodyBottom(){
				return `bottom:${uni.upx2px(105) + this.keyboardHeight}px; top:${this.navBarHeight}px;`	
			},
			// 获取操作列表或者表情列表
			emoticonOrActionList(){
				if(this.mode === 'emoticon' || this.mode === 'action'){
					return this[this.mode+'List']
				}
				return []
			},
			// 获取所有信息图片的地址
			imageList(){
				let arr = []
				this.list.forEach(item =>{
					if(item.type === "emoticon" || item.type === "image"){
						arr.push(item.data)
					}
				})
				return arr
			}
		},
		watch:{
			mode(newValue){
				if(newValue !== "action" && newValue !== "emoticon")
					this.$refs.action.hide()
				if(newValue !== "text")
					uni.hideKeyboard()
			}
		},
		components:{
			freeNavBar,
			freeIconButton,
			freeChatItem,
			freePopup,
			freeMainButton
		}
	}
</script>

<style>

</style>
